home *** CD-ROM | disk | FTP | other *** search
/ Skunkware 5 / Skunkware 5.iso / src / X11 / xpaint-2.1.1 / grab.c < prev    next >
C/C++ Source or Header  |  1995-05-03  |  9KB  |  360 lines

  1. /* +-------------------------------------------------------------------+ */
  2. /* | Copyright 1993, David Koblas (koblas@netcom.com)                  | */
  3. /* |                                                                   | */
  4. /* | Permission to use, copy, modify, and to distribute this software  | */
  5. /* | and its documentation for any purpose is hereby granted without   | */
  6. /* | fee, provided that the above copyright notice appear in all       | */
  7. /* | copies and that both that copyright notice and this permission    | */
  8. /* | notice appear in supporting documentation.  There is no           | */
  9. /* | representations about the suitability of this software for        | */
  10. /* | any purpose.  this software is provided "as is" without express   | */
  11. /* | or implied warranty.                                              | */
  12. /* |                                                                   | */
  13. /* +-------------------------------------------------------------------+ */
  14.  
  15. #include <X11/Intrinsic.h>
  16. #include <X11/cursorfont.h>
  17. #include "image.h"
  18.  
  19. #define GRAB_FAST
  20.  
  21. /*
  22. **  Convienence function.  For doing server pointer grabs
  23. **
  24. */
  25. #define GRAB_INTERVAL    30
  26.  
  27. typedef struct {
  28.     XtAppContext    app;
  29.     Display        *dpy;
  30.     GC        gc;
  31.     Window        root;
  32.     Boolean        drawn;
  33.     int        x, y, ox, oy, width, height;
  34.     XtIntervalId    id;
  35. } GrabInfo;
  36.  
  37. static void grabHilite(XtPointer infoArg, XtIntervalId *id)
  38. {
  39.     GrabInfo    *info = (GrabInfo*)infoArg;
  40.  
  41.     if (info->drawn) {
  42.         if (info->ox == info->x && info->oy == info->y)
  43.             goto end;
  44.  
  45.         XDrawRectangle(info->dpy, info->root, info->gc,
  46.             info->ox - info->width / 2, 
  47.             info->oy - info->height / 2,
  48.             info->width, info->height);
  49.     }
  50.     info->drawn = True;
  51.  
  52.     XDrawRectangle(info->dpy, info->root, info->gc,
  53.             info->x - info->width / 2, 
  54.             info->y - info->height / 2,
  55.             info->width, info->height);
  56.     info->ox = info->x;
  57.     info->oy = info->y;
  58.  
  59. end:
  60.     info->id     = XtAppAddTimeOut(info->app, GRAB_INTERVAL, 
  61.                     grabHilite, (XtPointer)info);
  62. }
  63.  
  64. static void xyToWindowCmap(Display *dpy, int x, int y, Window base,
  65.                      int *nx, int *ny, Window *window, Colormap *cmap)
  66. {
  67.     Window            twin;
  68.     Colormap        tmap;
  69.     Window            child, sub;
  70.     XWindowAttributes    attr;
  71.  
  72.     twin = base;
  73.     tmap = None;
  74.  
  75.     sub = base;
  76.     *nx = x;
  77.     *ny = y;
  78.  
  79.     while (sub != None) {
  80.         x = *nx;
  81.         y = *ny;
  82.         child = sub;
  83.         XTranslateCoordinates(dpy, base, child, x, y, nx, ny, &sub);
  84.         base = child;
  85.  
  86.         XGetWindowAttributes(dpy, child, &attr);
  87.         if (attr.class == InputOutput && attr.colormap != None) {
  88.             tmap = attr.colormap;
  89.             twin = child;
  90.         }
  91.     }
  92.  
  93.     if (tmap == None)
  94.         *cmap = DefaultColormap(dpy, DefaultScreen(dpy));
  95.     else
  96.         *cmap = tmap;
  97.     *window = twin;
  98. }
  99.  
  100. static void    doGrab(Widget w, int width, int height, int *x, int *y)
  101. {
  102.     Display            *dpy = XtDisplay(w);
  103.     XtAppContext         app  = XtWidgetToApplicationContext(w);
  104.     Window            root = DefaultRootWindow(dpy);
  105.     XEvent            event;
  106.     Cursor            cursor = XCreateFontCursor(dpy, XC_crosshair);
  107.     int            count = 0;
  108.     GrabInfo        *info = NULL;
  109.  
  110.     if (width != 0 && height != 0) {
  111.         XGCValues    gcv;
  112.         info = XtNew(GrabInfo);
  113.         gcv.function = GXxor;
  114.         gcv.foreground = 1;
  115.         gcv.subwindow_mode = IncludeInferiors;
  116.         info->root   = root;
  117.         info->app    = app;
  118.         info->x      = 0;
  119.         info->y      = 0;
  120.         info->drawn  = False;
  121.         info->dpy    = dpy;
  122.         info->gc     = XCreateGC(dpy, root, GCSubwindowMode|GCForeground|GCFunction, &gcv);
  123.         info->width  = width;
  124.         info->height = height;
  125.         info->id     = XtAppAddTimeOut(app, GRAB_INTERVAL, 
  126.                         grabHilite, (XtPointer)info);
  127.     }
  128.  
  129.     if (XGrabPointer(dpy, root, False,
  130.             info == NULL ? ButtonPressMask|ButtonReleaseMask
  131.                      : ButtonPressMask|ButtonReleaseMask|PointerMotionMask,
  132.             GrabModeSync, GrabModeAsync, 
  133.             root, cursor, CurrentTime)) {
  134.         return;
  135.     }
  136.  
  137.     do {
  138.         XAllowEvents(dpy, SyncPointer, CurrentTime);
  139.         XtAppNextEvent(app, &event); 
  140.         if (event.type == ButtonPress)
  141.             count++;
  142.         else if (event.type == ButtonRelease) {
  143.             if (count == 1)
  144.                 break;
  145.             else
  146.                 count--;
  147.         } else if (event.type == MotionNotify) {
  148.             info->x = event.xmotion.x;
  149.             info->y = event.xmotion.y;
  150.         } else 
  151.             XtDispatchEvent(&event);
  152.     } while (True);
  153.  
  154.     XUngrabPointer(dpy, CurrentTime);
  155.  
  156.     if (info != NULL) {
  157.         if (info->drawn)
  158.             XDrawRectangle(info->dpy, info->root, info->gc,
  159.                 info->ox - info->width / 2, 
  160.                 info->oy - info->height / 2,
  161.                 info->width, info->height);
  162.         XtRemoveTimeOut(info->id);
  163.         XFreeGC(XtDisplay(w), info->gc);
  164.         XtFree((XtPointer)info);
  165.     }
  166.  
  167.     *x = event.xbutton.x;
  168.     *y = event.xbutton.y;
  169. }
  170.  
  171. void    *DoGrabImage(Widget w, int width, int height)
  172. {
  173.     Screen        *screen = XtScreen(w);
  174.     Display        *dpy    = XtDisplay(w);
  175.     Window        root    = RootWindowOfScreen(screen);
  176.     Colormap    dmap    = DefaultColormapOfScreen(screen);
  177.     int        x, y, xi, yi, count, nx, ny, i, tx, ty;
  178.     int        fx, fy;
  179.     Colormap    cmap, lastCmap;
  180.     Window        window, lastWindow;
  181.     unsigned char    *ip;
  182.     Image        *image;
  183.     XColor        *xcol;
  184.     XImage        *xim;
  185.  
  186.     doGrab(w, width, height, &x, &y);
  187.  
  188.     x -= width  / 2;
  189.     y -= height / 2;
  190.  
  191.     if (x < 0) {
  192.         width += x;
  193.         x = 0;
  194.     }
  195.     if (y < 0) {
  196.         height += y;
  197.         y = 0;
  198.     }
  199.     if (x + width > WidthOfScreen(screen))
  200.         width = WidthOfScreen(screen) - x;
  201.     if (y + height > HeightOfScreen(screen))
  202.         height = HeightOfScreen(screen) - x;
  203.  
  204.     if (width == 0 || height == 0)
  205.         return NULL;
  206.  
  207.     image = ImageNew(width, height);
  208.     ip = image->data;
  209.  
  210.     xcol = (XColor *)XtCalloc(width, sizeof(XColor));
  211. #ifdef GRAB_FAST
  212.     /*
  213.     **  Fast grabs, just use the colormap at the 0,0 position 
  214.     **    gotcha is that the XImage is from the root window
  215.     **    thus, with it's depth.
  216.     */
  217.  
  218.     xyToWindowCmap(dpy, x, y, root, &nx, &ny, &window, &cmap);
  219.     xyToWindowCmap(dpy, x + width, y + height, root, &tx, &ty, &lastWindow, &lastCmap);
  220.  
  221.     /*
  222.     **  XXX Improvment:
  223.     **      instead of window == lastWindow
  224.     **      we could check for common parent, and use that.
  225.     */
  226.     if (window == lastWindow)
  227.         xim = XGetImage(dpy, window, nx, ny, width, height, AllPlanes, ZPixmap);
  228.     else
  229.         xim = XGetImage(dpy, root, x, y, width, height, AllPlanes, ZPixmap);
  230.  
  231.     for (y = 0; y < height; y++) {
  232.         for (x = 0; x < width; x++) {
  233.             xcol[x].pixel = XGetPixel(xim, x, y);
  234.             xcol[x].flags = DoRed|DoGreen|DoBlue;
  235.         }
  236.         XQueryColors(XtDisplay(w), cmap, xcol, width);
  237.         for (x = 0; x < width; x++) {
  238.             *ip++ = (xcol[x].red   >> 8) & 0xff;
  239.             *ip++ = (xcol[x].green >> 8) & 0xff;
  240.             *ip++ = (xcol[x].blue  >> 8) & 0xff;
  241.         }
  242.     }
  243. #else
  244.     /*
  245.     **  Slow grabs, get the correct color and colormap though a lot of
  246.     **    server calls.
  247.     */
  248.     StateSetBusyWatch(True);
  249.  
  250.     for (yi = 0; yi < height; yi++) {
  251.         count = 0;
  252.         lastCmap   = None;
  253.         lastWindow = None;
  254.         for (xi = 0; xi < width; xi++, count++) {
  255.             xyToWindowCmap(dpy, xi + x, yi + y, root, &nx, &ny, &window, &cmap);
  256.             if ((window != lastWindow || cmap != lastCmap) && count != 0) {
  257.                 if (cmap == lastCmap && lastWindow == root)
  258.                     continue;
  259.  
  260.                 xim = XGetImage(dpy, lastWindow, fx, fy, count, 1, 
  261.                         AllPlanes, ZPixmap);
  262.  
  263.                 for (i = 0; i < count; i++) {
  264.                     xcol[i].pixel = XGetPixel(xim, i, 0);
  265.                     xcol[i].flags = DoRed|DoGreen|DoBlue;
  266.                 }
  267.                 XQueryColors(XtDisplay(w), lastCmap, xcol, count);
  268.  
  269.                 for (i = 0; i < count; i++) {
  270.                     *ip++ = (xcol[i].red   >> 8) & 0xff;
  271.                     *ip++ = (xcol[i].green >> 8) & 0xff;
  272.                     *ip++ = (xcol[i].blue  >> 8) & 0xff;
  273.                 }
  274.  
  275.                 XDestroyImage(xim);
  276.  
  277.                 count = 0;
  278.             }
  279.  
  280.             if (count == 0) {
  281.                 fx = nx;
  282.                 fy = ny;
  283.                 if (cmap == dmap) {
  284.                     fx = x + xi;
  285.                     fy = y + yi;
  286.                     lastWindow = root;
  287.                 } else {
  288.                     lastWindow = window;
  289.                 }
  290.                 lastCmap   = cmap;
  291.             }
  292.         }
  293.         if (count != 0) {
  294.             xim = XGetImage(dpy, lastWindow, fx, fy, count, 1, 
  295.                     AllPlanes, ZPixmap);
  296.  
  297.             for (i = 0; i < count; i++) {
  298.                 xcol[i].pixel = XGetPixel(xim, i, 0);
  299.                 xcol[i].flags = DoRed|DoGreen|DoBlue;
  300.             }
  301.             XQueryColors(XtDisplay(w), lastCmap, xcol, count);
  302.  
  303.             for (i = 0; i < count; i++) {
  304.                 *ip++ = (xcol[i].red   >> 8) & 0xff;
  305.                 *ip++ = (xcol[i].green >> 8) & 0xff;
  306.                 *ip++ = (xcol[i].blue  >> 8) & 0xff;
  307.             }
  308.  
  309.             XDestroyImage(xim);
  310.         }
  311.     }
  312.  
  313.     StateSetBusyWatch(False);
  314. #endif
  315.  
  316.     XtFree((XtPointer)xcol);
  317.     XDestroyImage(xim);
  318.  
  319.     return (void*)image;
  320. }
  321.  
  322. void DoGrabPixel(Widget w, Pixel *p, Colormap *cmap)
  323. {
  324.     int        x, y, nx, ny;
  325.     XImage        *xim;
  326.     Colormap    amap;
  327.     Window        root = RootWindowOfScreen(XtScreen(w));
  328.     Window        window;
  329.     Display        *dpy = XtDisplay(w);
  330.  
  331.     doGrab(w, 0, 0, &x, &y);
  332.  
  333.     if (cmap == NULL)
  334.         cmap = &amap;
  335.  
  336.     xyToWindowCmap(dpy, x, y, root, &nx, &ny, &window, cmap);
  337.  
  338.     xim = XGetImage(dpy, window, nx, ny, 1, 1, AllPlanes, ZPixmap);
  339.  
  340.     if (p != NULL)
  341.         *p = XGetPixel(xim, 0, 0);
  342.  
  343.     XDestroyImage(xim);
  344. }
  345.  
  346. XColor    *DoGrabColor(Widget w)
  347. {
  348.     static XColor    xcol;
  349.     Colormap    cmap;
  350.     Pixel        p;
  351.  
  352.     DoGrabPixel(w, &p, &cmap);
  353.  
  354.     xcol.pixel = p;
  355.     xcol.flags = DoRed|DoGreen|DoBlue;
  356.     XQueryColor(XtDisplay(w), cmap, &xcol);
  357.  
  358.     return &xcol;
  359. }
  360.